package st.learnopengl.apps.basic

import glm_.vec4.Vec4i
import gln.BufferTarget
import gln.Usage
import gln.VertexAttrType
import gln.draw.DrawMode
import gln.draw.glDrawArrays
import gln.glViewport
import gln.glf.VertexAttribute
import gln.identifiers.GlBuffer
import gln.identifiers.GlProgram
import gln.vertexArray.glEnableVertexAttribArray
import gln.vertexArray.glGenVertexArray
import gln.vertexArray.glVertexAttribPointer
import st.learnopengl.common.App
import st.learnopengl.common.GLUT
import org.lwjgl.opengl.GL11
import org.lwjgl.opengl.GL15
import org.lwjgl.opengl.GL15.glGenBuffers
import org.lwjgl.opengl.GL30
import java.nio.ByteBuffer
import java.nio.ByteOrder

class Shaders(width: Int, height: Int, title: String): App(width, height, title) {
    private var program: GlProgram? = null
    private var vao : Int = -1
    private var vbo: GlBuffer? = null
    private lateinit var vboAttr: VertexAttribute
    private lateinit var colorAttr: VertexAttribute
    private var typeLocation: Int = -1
    override fun onInit() {
        program = GLUT.createProgram("shaders/basics/vertexShader.glsl"
            , "shaders/basics/colorFragmentShader.glsl")
        typeLocation = program!!.getUniformLocation("type")
        vao = glGenVertexArray()
        GL30.glBindVertexArray(vao)
        vbo = GlBuffer(glGenBuffers())
        vbo?.bound(BufferTarget.ARRAY) {
            val vertexs = listOf<Float>(
                -0.5f, -0.5f, 0.0f, /* left */ 1.0f, 0.0f, 0.0f, /* red */
                0.5f, -0.5f, 0.0f,  /* right */ 0.0f, 1.0f, 0.0f, /* green */
                0.0f,  0.5f, 0.0f,  /* top  */ 0.0f, 0.0f, 1.0f /* blue */
            )
            val bb = ByteBuffer.allocateDirect(vertexs.size * 4)
            bb.order(ByteOrder.nativeOrder())
            val fb = bb.asFloatBuffer()
            vertexs.forEach {
                fb.put(it)
            }
            fb.position(0)
            data(fb, Usage.STATIC_DRAW)
        }

        vboAttr =  VertexAttribute(0, 3, VertexAttrType.FLOAT, false, 6 * 4, 0)
        colorAttr = VertexAttribute(1, 3, VertexAttrType.FLOAT, false, 6 * 4, 3 *4)

        GL15.glClearColor(0.3f, 0.3f, 0.3f, 1.0f)
    }

    override fun loop() {
        glViewport(Vec4i(0, 0, width, height))
        GL15.glClear(GL15.GL_COLOR_BUFFER_BIT)

        glViewport(Vec4i(0, 0, width / 2, height / 2))
        // program type = 1
        program?.use()
        program?.programUniform(typeLocation, 1)
        vbo?.bind(BufferTarget.ARRAY)

        glEnableVertexAttribArray(vboAttr)
        glVertexAttribPointer(vboAttr)

        GL11.glDrawArrays(GL11.GL_TRIANGLES, 0, 3)

        glViewport(Vec4i(width / 2, 0, width / 2, height / 2))
        // program type = 2
        program?.use()
        program?.programUniform(typeLocation, 2)
        vbo?.bind(BufferTarget.ARRAY)

        vboAttr.enable()
        vboAttr.pointer()

        colorAttr.enable()
        colorAttr.pointer()

        glDrawArrays(DrawMode.TRIANGLES, 3)

        vboAttr.disable()
        colorAttr.disable()

        glViewport(Vec4i(0, height / 2, width / 2, height / 2))
        // program type = 0
        program?.use()
        program?.programUniform(typeLocation, 0)
        vboAttr.enable()
        vboAttr.pointer()

        glDrawArrays(DrawMode.TRIANGLES, 3)

        vboAttr.disable()
        vbo?.unbind(BufferTarget.ARRAY)
        program?.unuse()
    }


    companion object {
        @JvmStatic
        fun main(args: Array<String>) {
            val app = Shaders(1280, 720, "Shaders")
            app.run()
        }
    }
}